/*
 * glReflection.cpp
 *
 *  Created on: 10.11.2012
 *      Author: Martin
 */

#ifdef _WIN32 
#include <windows.h> 
#endif

#include "glReflection.h"

glReflection::glReflection(Water *_water)
{
	water = _water;

	// default value of texture unit
	RefTexture = 0;
	ViewBuffer = glm::mat4(0.0);

	// The framebuffer, which regroups 0, 1, or more textures, and 0 or 1 depth buffer.

	glGenFramebuffers(1, &FramebufferName);
	glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);

	glGenTextures(1, &RefTexture);
	glBindTexture(GL_TEXTURE_2D, RefTexture);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, Engine::screenSettings.screenWidth,
			Engine::screenSettings.screenHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
			RefTexture, 0);

	// The depth buffer
	glGenRenderbuffers(1, &depthrenderbuffer);
	glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT,
			Engine::screenSettings.screenWidth, Engine::screenSettings.screenHeight);
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
			GL_RENDERBUFFER, depthrenderbuffer);

	// Set the list of draw buffers.
	GLenum DrawBuffers[2] =
	{ GL_COLOR_ATTACHMENT0 };
	glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers

	// check buffer
	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
		std::cerr << "Unable to use frame buffer.\n" << std::endl;
}

glReflection::~glReflection()
{
	glDeleteTextures(1, &RefTexture); // delete texture unit

	// delete depth texture
	glDeleteBuffers(1, &FramebufferName);
	glDeleteBuffers(1, &depthrenderbuffer);
}

// starting render to texture
void glReflection::glReflectionBegin()
{
	glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);

	// clear screen
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// save view matrix
	ViewBuffer = World::world->getView();
	// turn view matrix upside down
	// and translate when water surface isn't on 0.0 y position
	glm::mat4 View = glm::scale(ViewBuffer, glm::vec3(1.0f, -1.0f, 1.0f));
	float h = water->getHigh() * -2.0;
	View = glm::translate(View, glm::vec3(0.0f, h - 0.1, 0.0f));

	World::world->setView(View);

}

// end of texture render, return texture ID
GLuint glReflection::glReflectionEnd()
{
	glBindFramebuffer(GL_FRAMEBUFFER, 0);

	// clear screen
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// set view port back to screen size
	glViewport(0, 0, Engine::screenSettings.screenWidth,
			Engine::screenSettings.screenHeight);

	// set back old view matrix
	World::world->setView(ViewBuffer);

	return RefTexture; // return texture
}

